Skip to content

在 .NET 使用 MQTT:MQTTnet 與 Mosquitto 實作

TLDR

  • MQTT 採用發佈/訂閱模式,核心角色包含 Broker、Publisher、Subscriber 與 Topic。
  • Topic 建議採用階層化命名(如 home/living-room/temperature),並避免使用 $ 開頭(保留給系統使用)。
  • QoS 等級決定傳輸可靠性:QoS 0(最多一次)、QoS 1(至少一次)、QoS 2(確保一次)。
  • 實際傳輸 QoS 取決於 Publisher 與 Subscriber 設定中的最小值。
  • 使用 Docker 架設 Mosquitto 時,務必設定 persistence 以保留訊息,並透過 entrypoint.sh 處理權限與帳號初始化。
  • MQTTnet 實作中,Last Will 僅在異常斷線時觸發;Retained Message 適用於儲存最新狀態。
  • MQTT 5.0 的持久會話需同時設定 CleanStart = falseSessionExpiryInterval > 0

MQTT 基本概念與運作

MQTT (Message Queuing Telemetry Transport) 是一種輕量級的發佈/訂閱式訊息傳輸協定,適合 IoT 裝置通訊。

核心角色

  • Broker:系統核心,負責接收、過濾與分發訊息。
  • Publisher:發佈訊息的客戶端。
  • Subscriber:訂閱主題以接收訊息的客戶端。
  • Topic:訊息分類標籤,結構類似檔案路徑。

Topic 命名規則與限制

什麼情況下會遇到命名問題:在設計主題階層時,若未遵守規範,容易導致訂閱失敗或權限衝突。

  • 階層分隔:使用 / 分隔。
  • 區分大小寫Home/Temphome/temp 為不同主題。
  • 系統主題$ 開頭的主題(如 $SYS/)保留給 Broker 使用,應用程式不應佔用。
  • 萬用字元+(單層)與 #(多層)僅能用於訂閱,不能用於發佈。

QoS(服務品質等級)

什麼情況下會遇到 QoS 選擇困難:當系統對訊息遺失或重複的容忍度不同時,需選擇對應的 QoS 等級。

  • QoS 0:效能最高,訊息可能遺失,適用於頻繁更新的感測資料。
  • QoS 1:確保送達,但可能收到重複訊息,適用於控制指令。
  • QoS 2:四次握手,確保不遺失也不重複,適用於金融或計費系統。

最終 QoS 計算公式實際 QoS = min(發佈 QoS, 訂閱 QoS)


使用 Docker Compose 架設 Mosquitto

什麼情況下會遇到架設問題:在容器化環境中,若未正確設定權限或持久化,會導致重啟後資料遺失或無法寫入設定檔。

關鍵設定檔 (mosquitto.conf)

conf
listener 1883
protocol mqtt
allow_anonymous false
password_file /mosquitto/config/password.txt
persistence true
persistence_location /mosquitto/data/

啟動腳本 (entrypoint.sh)

必須確保容器內的 UID 1883 擁有資料夾權限:

shell
#!/bin/sh
chown -R 1883:1883 /mosquitto/config /mosquitto/log /mosquitto/data
exec mosquitto -c /mosquitto/config/mosquitto.conf

.NET 使用 MQTTnet 實作

基礎發佈與訂閱

使用 MQTTnet 建立連線並訂閱主題的範例:

csharp
// 訂閱範例
var subscribeOptions = new MqttClientSubscribeOptionsBuilder()
    .WithTopicFilter(f => f.WithTopic("test/topic").WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce))
    .Build();
await client.SubscribeAsync(subscribeOptions);

// 發佈範例
var message = new MqttApplicationMessageBuilder()
    .WithTopic("test/topic")
    .WithPayload("Hello, MQTT!")
    .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce)
    .Build();
await client.PublishAsync(message);

進階功能實作

遺囑訊息 (Last Will and Testament)

什麼情況下會用到:當需要監控設備是否「異常離線」時。

  • 正常呼叫 DisconnectAsync() 不會觸發遺囑。
  • 僅在網路中斷或程式崩潰時,Broker 會自動發佈預設的遺囑訊息。

持久會話 (Persistent Session)

什麼情況下會用到:當客戶端斷線後,希望重新連線時能收到離線期間累積的 QoS 1/2 訊息。

MQTT 5.0 實作建議

csharp
var options = new MqttClientOptionsBuilder()
    .WithClientId("client-001")
    .WithCleanStart(false)              // 嘗試使用現有 Session
    .WithSessionExpiryInterval(600)     // 斷線後保留 10 分鐘
    .Build();

TIP

本篇的完整可執行範例:CloudyWing/MqttNetMosquittoSample


異動歷程

    • 初版文件建立。
    • 補上對應 GitHub 範例專案連結。